﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace EpiMapit
{
    public class CaseSetAccumulator
    {

        public CaseSetGroup Transform(CaseSetGroup group)
        {
            var result = new CaseSetGroup();

            var orderedCases = group.OrderBy(g => g.Date).OrderBy(g => g.RegionCode).GroupBy(g => g.RegionCode);
            var allDates = group.Select(g => g.Date).Distinct().OrderBy(d => d).ToList();

            foreach (var ggg in orderedCases)
            {
                bool first = true;
                Dictionary<string, int> accumulation = new Dictionary<string, int>();

                int indexInAllDates = 0;
                CaseSet lastCase = null;

                foreach (var kaze in ggg)
                {
                    while (allDates[indexInAllDates] != kaze.Date)
                    {
                        if (!first)
                        {
                            var newCase = new CaseSet()
                            {
                                Levels = lastCase.Levels,
                                Date = allDates[indexInAllDates],
                                Lat = lastCase.Lat,
                                Lon = lastCase.Lon,
                                RegionCodes = lastCase.RegionCodes,
                            };
                            result.Add(newCase);
                        }

                        indexInAllDates++;
                    }

                    Merge(accumulation, kaze.Levels);

                    if (first)
                    {
                        var newCase = new CaseSet()
                        {
                            Levels = kaze.Levels,
                            Date = kaze.Date,
                            Lat = kaze.Lat,
                            Lon = kaze.Lon,
                            RegionCodes = kaze.RegionCodes,
                        };
                        result.Add(newCase);
                        first = false;
                    }
                    else
                    {
                        var set = new CaseSet() 
                        {
                            Levels = Clone(accumulation),
                            Date = kaze.Date,
                            Lat = kaze.Lat,
                            Lon = kaze.Lon,
                            RegionCodes = kaze.RegionCodes,
                        };

                        result.Add(set);
                    }

                    indexInAllDates++;
                    lastCase = kaze;
                }

                while (indexInAllDates < allDates.Count)
                {
                    lastCase = result.Last();
                    var newCase = new CaseSet()
                    {
                        Levels = lastCase.Levels,
                        Date = allDates[indexInAllDates],
                        Lat = lastCase.Lat,
                        Lon = lastCase.Lon,
                        RegionCodes = lastCase.RegionCodes,
                    };
                    result.Add(newCase);

                    indexInAllDates++;
                }
            }

            return result;
        }

        private Dictionary<string, int> Clone(Dictionary<string, int> dictionary)
        {
            Dictionary<string, int> result = new Dictionary<string, int>();
            foreach (var entry in dictionary)
            {
                result.Add(entry.Key, entry.Value);
            }
            return result;
        }

        private void Merge(Dictionary<string, int> result, Dictionary<string, int> other)
        {
            foreach (var entry in other)
            {
                int value;
                if (result.TryGetValue(entry.Key, out value))
                {
                    result[entry.Key] += entry.Value;
                }
                else
                {
                    result.Add(entry.Key, entry.Value);
                }
            }
        }

    }
}
